#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "../../src/cdslib.h"

#define cast(x) (void *)(x)

typedef struct {
    long value;
} Long;

void initLong(Long *initThis, long newValue) {
    initThis->value = newValue;
}

Long *newLong(long newValue) {
    Long *toReturn = malloc(sizeof(Long));
    initLong(toReturn, newValue);
    return toReturn;
}

void deleteLong(Long *l) {
    if(l != NULL) {
        free(l);
    }
}

int compareLong(const void *l1, const void *l2) {
    return ((Long *)l1)->value - ((Long *)l2)->value;
}

int main() 
{
    Long getMe;
    size_t i;
    HashMap h;
    Array temp;
    Pair p;
    initHashMap(&h, sizeof(Long), NULL, &compareLong);

    /* Testing length */
    assert(h.length == 0);

    /* 
     * Using h as a psuedo-contact book where phone numbers (Longs) are the
     * keys and names (strings) are the values.
     */
    HashMapSet(&h, newLong(1235559799), "John Smith");
    HashMapSet(&h, newLong(1235557978), "Mary Smith");

    assert(h.length == 2);

    /* asserting that h contains the 2 entries we just added */
    initLong(&getMe, 1235559799);
    assert(HashMapContainsKey(&h, &getMe) == 1);
    initLong(&getMe, 1235557978);
    assert(HashMapContainsKey(&h, &getMe) == 1);

    /* asserting that getting values based on keys works correctly */
    initLong(&getMe, 1235559799);
    assert(strcmp("John Smith", (char *)HashMapGet(&h, &getMe)) == 0);
    initLong(&getMe, 1235557978);
    assert(strcmp("Mary Smith", (char *)HashMapGet(&h, &getMe)) == 0);

    /* 
     * Asserting something we haven't added to h comes back as NULL,
     * and that the key is not in h.
     */
    initLong(&getMe, 1235554321);
    assert(HashMapContainsKey(&h, &getMe) == 0); /* Testing key isn't in h. */
    assert(HashMapGet(&h, &getMe) == NULL);      /* Testing value isn't in h. */

    /* deleting an index from h */
    initLong(&getMe, 1235557978);
    p = HashMapExtract(&h, &getMe);
    deleteLong(p.first);

    /* 
     * ArrayGet(&temp, 1) is just a pointer to a string, 
     * but not a malloced one. So no need for a free.
     */
    assert(h.length == 1);

    /* setting a key to a new value */
    p = HashMapSet(&h, newLong(1235559799), "Joe Smith");
    deleteLong(p.first);
    assert(h.length == 1);

    /* making sure that set went along correctly */
    initLong(&getMe, 1235559799);
    assert(strcmp("Joe Smith", (char *)HashMapGet(&h, &getMe)) == 0);
  
    temp = deleteHashMap(&h);
    for(i = 0; i < temp.length; i += 2) {
        deleteLong(ArrayGet(&temp, i));
    }
    deleteArray(&temp);

    return EXIT_SUCCESS;
}
